﻿using System.Diagnostics;

namespace ThreadTimeOutDemo
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            var time = Stopwatch.StartNew();
            Thread thread = new Thread(Foo);
            thread.Start();

            if (!thread.Join(TimeSpan.FromSeconds(2)))
            {
                thread.Interrupt();
            }
            Console.WriteLine("Hello, World!" + time.ElapsedMilliseconds.ToString());




            #region Task的超时
            var cts = new CancellationTokenSource();
            //方法1
            //var footask = Foo1(cts.Token);
            //Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
            //var completedTask = await Task.WhenAny(footask, Task.Delay(TimeSpan.FromSeconds(2)));
            //if (completedTask != footask)
            //{
            //    cts.Cancel();
            //    await footask;
            //    Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}" + "Foo timed out.");
            //}
            //方法2
            try
            {
                await Foo1(cts.Token).WaitAsync(TimeSpan.FromSeconds(2));
                Console.WriteLine("Foo completed.");
            }
            catch (TimeoutException)
            {
                cts.Cancel();
                Console.WriteLine("TimeOut");
            }
            #endregion


            Console.ReadKey();
        }

        static void Foo()
        {
            try
            {
                Console.WriteLine("Foo start...");
                Thread.Sleep(10000);
                Console.WriteLine("Foo end...");
            }
            catch (ThreadInterruptedException)
            {
                Console.WriteLine("Foo interrupted...");
            }
        }

        static async Task Foo1(CancellationToken cancellationToken)
        {
            try
            {
                Console.WriteLine("Foo start...");
                await Task.Delay(5000, cancellationToken);
                Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}" + "Foo end...");
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine("Foo canceled...");
            }
        }
    }

    static class AsyncExtension
    {
        public static async Task TimeAfter(this Task task, TimeSpan timeout)
        {
            using var cts = new CancellationTokenSource();
            var completedTask = await Task.WhenAny(task, Task.Delay(timeout, cts.Token));
            if (completedTask != task)
            {
                cts.Cancel();
                throw new TimeoutException();
            }
            await task;
        }   
    }
}
